<?php
/**
 * Class UserLogic
 * @package app\common\logic
 */

namespace app\common\logic;
use think\Log;

/**
 * 上传文件相关逻辑
 *
 * @package app\common\logic
 */
class Upload extends Base
{

    //允许的文件后缀
    private $file_ext;
    //允许的文件类型
    private $file_mime_type;

    private $request;

    //文件上传的顶级目录
    private $uploadPath;

    //单个类型的文件总数限制
    private $fileLimitCounts = 1;

    //单个文件的大小限制（字节）
    private $fileEachLimitSize;


    public function __construct($data = [])
    {
        parent::__construct($data);
        $this->request = request();

        $this->setUploadExt();
        $this->setMimeType();
        $this->setUploadPath();
        $this->setfileEachLimitSize(2);
    }

    /**
     * 设置上传文件的后缀
     * @param array $ext
     */
    public function setUploadExt(array $ext = [])
    {
        $this->file_ext = $ext ? $ext : ['xls','xlsx'];
    }

    /**
     * 设置上传文件的mime类型
     * @param array $mime
     */
    public function setMimeType(array $mime = [])
    {
        $this->file_mime_type = $mime ? $mime : ['application/vnd.ms-excel','application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'];
    }

    /**
     * 设置上传文件的mime类型
     * @param string $path
     */
    public function setUploadPath($path = '')
    {
        $this->uploadPath = $path ? $path : UPLOAD_FILE_PATH;
    }

    /**
     * 设置上传文件的mime类型
     * @param int $size_limit 单位：M
     */
    public function setfileEachLimitSize($size_limit = 2)
    {
        $this->fileEachLimitSize = $size_limit * 1024 * 1024;
    }

    /**
     * 文件上传
     *
     * @author mayy
     * @date 2017-8-15
     * @param string $save_name
     * @param string $file_ext
     * @param bool $need_in_db
     * @return array
     */
    public function uploadFile($save_name='', $file_ext = '', $need_in_db = false)
    {
        // 获取表单上传文件
        $files = $this->request->file('file');
        if (empty($files)) {
            //没有图片上传
            exception('没有文件上传或文件已经超出系统最大限制！');
        }

        //数量验证
        if (count($files) > $this->fileLimitCounts) {
            exception('文件数量超出限制！');
        }

        //大小验证
        foreach($files as $file){
            $file_info = $file->getInfo();
            if ($file_info['size'] > $this->fileEachLimitSize) {
                Log::record('上传的文件文件超出限制：' . $file_info['size']);
                exception('文件大小超出限制（'.($this->fileEachLimitSize/1024/1024).'M）！');
            }
        }

        $flag = true;
        $file_url_saved = [];    //上传成功的文件物理地址

        foreach($files as $file){
            //图片存放规则： /mnt/www/File/项目名称/Img/图片类型/年月日/图片文件
            //存入数据库的部分为： 图片类型/年月日/图片文件

            $sava_path = $this->getFileUploadDir();
            if ($sava_path == false) {
                exception('文件上传路径生成失败，请联系工程师处理！');
            }

            //如果有同名文件，不覆盖
            if (!empty($save_name)) {
                $i = 1;
                $len = strlen($save_name);
                while (file_exists($sava_path.$save_name.'.'.$file_ext)) {
                    $save_name = substr($save_name, 0, $len);
                    $save_name = $save_name . '('.$i.')';
                    $i++;
                }
                $info = $file->validate(['ext'=>$this->file_ext])->move($sava_path, $save_name, false);
            } else {
                $info = $file->validate(['ext'=>$this->file_ext])->rule('uniqid')->move($sava_path, true, false);
            }

            if($info){
                //文件上传成功
                $file_url_saved[] = $sava_path . $info->getSaveName();
            }else{
                // 上传失败获取错误信息
                Log::record('文件上传失败，错误原因：' . $file->getError());
                $this->errorInfo = '上传文件保存失败('.$file->getError().')！';
                $flag = false;
                break;
            }
        }

        if (!$flag && !empty($file_url_saved)) {
            $this->delFileFromDisk($file_url_saved);
            $file_url_saved = [];
        }

        /*需要数据入库*/
        if ($need_in_db) {
            $upload_file_model = model('UploadFile');
            $upload_ids = [];
            foreach ($file_url_saved as $v) {
                $data = [
                    'url' => str_replace(UPLOAD_FILE_PATH, '', $v),
                ];
                $res_id = $upload_file_model->addData($data);
                if (!$res_id) {
                    return [];
                }
                $upload_ids[] = $res_id;
            }
            return $upload_ids;
        }

        return $file_url_saved;
    }

    /**
     * 删除磁盘上面的文件
     *
     * @author mayy
     * @date 2017-8-17
     * @param $url_saved
     * @param boolean $full_path 是否是完整的路径
     * @return bool
     */
    private function delFileFromDisk($url_saved, $full_path = true)
    {
        if (!is_array($url_saved)) {
            $url_saved = [$url_saved];
        }

        foreach ($url_saved as $v) {
            if (!$full_path) {
                $path = $this->uploadPath . $v;
            } else {
                $path = $v;
            }
            if (file_exists($path)) {
                @unlink($path);
            }
        }

        return true;
    }

    /**
     * 生成图片上传路径
     *
     * @return string
     */
    private function getFileUploadDir()
    {
        $dir = $this->uploadPath . date('ymd') . DIRECTORY_SEPARATOR;
        if (!file_exists($dir)) {
            $res = @mkdir($dir, 0755, true);
            if (!$res) {
                Log::record('路径创建失败：' . $dir);
                return false;
            }
        }
        return $dir;
    }


    /**
     * 检查图片上传数量是否超出限制.
     *
     * @author mayy
     * @date 2017-8-15
     * @param $table_name
     * @param $data_id
     * @param $upload_counts
     * @return bool
     */
    private function checkImgCounts($table_name, $data_id, $upload_counts)
    {
        $where = [
            'table_name' => $table_name,
            'table_id'   => $data_id,
        ];
        $uploaded = $this->imgModel->getList($where, 1, true);
        if (($upload_counts + $uploaded) > $this->imgLimitCounts) {
            Log::record('图片数量超出限制，已上传数量：' . $uploaded . '本次上传数量：' . $upload_counts);
            return false;
        }
        return true;
    }
    /**
     * 根据图片主键id删除图片,一个或者多个
     *
     * @author mayy
     * @date 2017-8-15
     * @param array $img_ids
     * @return bool
     */
    public function deleteImgById(array $img_ids)
    {
        if (empty($img_ids)) {
            return false;
        }

        $where = [
            'id' => $img_ids,
        ];

        return $this->delImgsByWhere($where);
    }

    /**
     * 根据条件删除图片
     *
     * @param array $where
     * @return bool
     */
    private function delImgsByWhere(array $where)
    {
        //取出全部图片对应的路径，然后删除图片记录，然后删除图片文件
        $imgs_data = $this->getImgListDiskUrl($where, 200);
        if ($imgs_data['total'] == 0 || empty($imgs_data['data'])) {
            //无记录可删
            return true;
        }

        $urls = array_column($imgs_data['data'], 'img_url');

        $res = $this->imgModel->delImgs($where);
        if ($res === false) {
            Log::record('删除图片记录失败：' . $this->imgModel->getLastSql());
            return false;
        }

        if ($res > $imgs_data['total']) {
            Log::record('删除图片行数异常：' . $this->imgModel->getLastSql());
            return false;
        }

        //删除磁盘对应文件
        $this->delImgFromDisk($urls);

        return true;
    }

    /**
     * 根据图片所属者的信息作为条件删除图片数据
     *
     * @author mayy
     * @date 2017-8-15
     * @param $table_name
     * @param $table_id
     * @param $img_type
     * @return bool
     */
    public function deleteImgsByData($table_name, $table_id, $img_type)
    {
        if (empty($table_name) || empty($table_id) || !in_array($img_type, $this->imgType)) {
            Log::record('删除图片请求参数错误：' . implode(',', func_get_args()));
            exception('缺少删除图片的必要参数！');
        }

        $where = [
            'table_name'=> $table_name,
            'table_id'  => is_array($table_id) ? $table_id : [$table_id],
            'img_type'  => $img_type,
        ];

        return $this->delImgsByWhere($where);
    }

    /**
     * 获取图片列表，返回的url为http可访问的地址
     *
     * @param $where
     * @param $limit
     */
    public function getImgListHttpUrl($where, $limit = 20)
    {
        $imgs_data = $this->imgModel->getList($where, $limit);
        if (!empty($imgs_data['data'])) {
            foreach ($imgs_data['data'] as &$v) {
                $v['img_url'] = !empty(['img_url']) ? get_img_http_url($v['img_url']) : '';
            }
        }

        return $imgs_data;
    }

    /**
     * 获取图片列表，返回的url为http可访问的地址
     *
     * @param $where
     * @param $limit
     */
    public function getImgListDiskUrl($where, $limit = 20)
    {
        $imgs_data = $this->imgModel->getList($where, $limit);
        if (!empty($imgs_data['data'])) {
            foreach ($imgs_data['data'] as &$v) {
                $v['img_url'] = !empty($v['img_url']) ? IMG_PATH . $v['img_url'] : '';
            }
        }

        return $imgs_data;
    }

}